/**
 * @file SceneUpdater.hpp
 *
 * Created on: 10/ott/2012
 * Author: alberto
 *
 */

#ifndef SCENEUPDATER_HPP_
#define SCENEUPDATER_HPP_

#include <osg/NodeCallback>
#include <osg/PositionAttitudeTransform>
#include <osgText/Text>
#include <osg/Timer>

#include "milling/Stock.hpp"
#include "milling/Cutter.hpp"
#include "InputDeviceStateType.hpp"
#include "MillingSignaler.hpp"
#include "DisplayInfo.hpp"

/**
 * @class SceneUpdater
 *
 * callback that updates the scene, plus the functions it uses
 */
class SceneUpdater : public osg::NodeCallback {

private:
	typedef void (SceneUpdater::* SignalInfoProcesser)(const SignaledInfo &);
	
private:
	/** needed by the scene updater, checks if the scene has to be updated */
	const InputDeviceStateType::Ptr IDST;
	/** keeps track of milling ops */
	const MillingSignaler::Ptr SIGNALER;
	
	/** stock and cutter moves */
	const osg::ref_ptr< osg::PositionAttitudeTransform > stockRototras,
			cutterRototras;
	
	/** textual messages to display */
	const osg::ref_ptr< osgText::Text > txtMoves,
		txtWaste, txtWater;
	
	/** pointer to the stock object */
	const Stock::Ptr stockPtr;
	/** pointer to the cutter object */
	const Cutter::Ptr cutterPtr;
	/** volume of the stock */
	const double stockVolume;
	
	/** number of frames displayed */
	unsigned long nFrames;
	/** number of moves performed */
	unsigned int nMoves;
	/** amount of removed material */
	double totWaste;
	/** true if the water flow is enabled */
	bool waterFlag;
	
	/** timer (of course...) */
	osg::Timer timer;
	/** pointers to the functions called: updateScene, millingEnd, timeoutExpired */
	SignalInfoProcesser PROCESSERS[3];
	
public:
	/**
	 * constructor
	 *
	 * prepares the scene for the changes, calls the right function to apply changes
	 *
	 * @param ids : needed by the scene updater, checks if the scene has to be updated
	 * @param signaler : keeps track of milling ops
	 * @param displayInfo : infos for the scene
	 * @param stock : pointer to the stock object
	 * @param cutter : pointer to the cutter object
	 */
	SceneUpdater(InputDeviceStateType::Ptr ids,
			MillingSignaler::Ptr signaler,
			const DisplayInfo &displayInfo,
			Stock::Ptr stock, Cutter::Ptr cutter);
	
	virtual ~SceneUpdater();
	
/**
 * the callback
 *
 * gets the scene tree node to be updated, recovers the infos generated by the milling ops,
 * calls the SceneUpdater constructor to apply the changes to the scene tree, continues traversing the scene tree
 * (makes the viewer continuing to work)
 *
 * @param node : the scene tree node to be updated
 * @param nv : the scene tree traverser (interface with the scene viewer)
 */	virtual void operator() ( osg::Node* node, osg::NodeVisitor* nv );
	
private:
 	/**
 	 * executed when a scene is updated, creating and displaying the new mesh for the stock and moving the cutter
 	 *
 	 * @param info : infos of the milling ops
 	 */
	void updateScene(const SignaledInfo &info);

	/**
	 * updates textual infos in the viewer
	 */
	void updateText();

	/**
	 * tells the world that milling is ended
	 *
	 * @param info : infos of the milling ops
	 */
	void millingEnd(const SignaledInfo &info);

	/**
	 * recognizes that the timeout has expired, does nothing (here for debugging purposes)
	 *
	 * @param info : infos of the milling ops
	 */
	void timeoutExpired(const SignaledInfo &info);
};

#endif /* SCENEUPDATER_HPP_ */
